package pers.ljf.escloud.service.modules.app.impl;

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.crypto.hash.Sha256Hash;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import pers.ljf.escloud.common.dto.AppLoginUserInfo;
import pers.ljf.escloud.common.req.EntSaveRequest;
import pers.ljf.escloud.common.req.UserSaveReq;
import pers.ljf.escloud.dao.entity.app.*;
import pers.ljf.escloud.dao.entity.sys.SysUserEntity;
import pers.ljf.escloud.dao.entity.sys.SysUserTokenEntity;
import pers.ljf.escloud.dao.mapper.app.UserMapper;
import pers.ljf.escloud.service.dto.Query;
import pers.ljf.escloud.service.modules.app.*;
import pers.ljf.escloud.service.modules.sys.SysUserService;
import pers.ljf.escloud.service.modules.sys.SysUserTokenService;
import pers.ljf.escloud.service.util.PageUtils;
import pers.ljf.escloud.service.util.TokenGenerator;

import javax.annotation.Resource;
import java.util.Date;
import java.util.Map;

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    //12小时后过期
    private final static int EXPIRE = 3600 * 12;

    @Resource
    private UserTokenService userTokenService;

    @Resource
    private BucketDeptService bucketDeptService;

    @Resource
    private BucketService bucketService;

    @Resource
    private DepartmentService departmentService;

    @Override
    public UserToken queryByToken(String accessToken) {
        return userTokenService.getOne(new QueryWrapper<UserToken>().eq("token", accessToken));
    }

    @Override
    public User queryUser(Long userId) {
        return getById(userId);
    }

    @Override
    public User queryByUserName(String username) {
        return getOne(new QueryWrapper<User>().eq("username", username));
    }

    @Override
    public UserToken createToken(Long userId) {
        //生成一个token
        String token = TokenGenerator.generateValue();

        //当前时间
        Date now = new Date();
        //过期时间
        Date expireTime = new Date(now.getTime() + EXPIRE * 1000);

        //判断是否生成过token
        UserToken tokenEntity = userTokenService.getById(userId);
        if (tokenEntity == null) {
            tokenEntity = new UserToken();
            tokenEntity.setUserId(userId);
            tokenEntity.setToken(token);
            tokenEntity.setUpdateTime(now);
            tokenEntity.setExpireTime(expireTime);
            tokenEntity.setAge(EXPIRE);
            //保存token
            userTokenService.save(tokenEntity);
        } else {
            tokenEntity.setToken(token);
            tokenEntity.setUpdateTime(now);
            tokenEntity.setExpireTime(expireTime);
            tokenEntity.setAge(EXPIRE);
            //更新token
            userTokenService.updateById(tokenEntity);
        }
        return tokenEntity;
    }

    @Override
    public void logout(Long userId) {

    }

    @Override
    public Bucket getBucket(Long id) {
        User user = getById(id);
        Assert.isTrue(null != user, "用户不存在");
        BucketDept bucketDept = bucketDeptService.getOne(new QueryWrapper<BucketDept>().eq("dept_id", user.getDeptId()));
        Assert.isTrue(null != bucketDept, "部门不存在存储bucket");
        Bucket bucket = bucketService.getById(bucketDept.getBucketId());
        return bucket;
    }

    @Override
    public AppLoginUserInfo getUserDetailInfo(User user) {
        Bucket bucket = getBucket(user.getId());
        AppLoginUserInfo userInfo = new AppLoginUserInfo();
        //user
        BeanUtils.copyProperties(user, userInfo);
        //oss
        userInfo.setBucketName(bucket.getBucketName());
        Department department = departmentService.getById(user.getDeptId());
        Assert.isTrue(null != department, "用户不存在部门");
        userInfo.setDeptName(department.getName());
        userInfo.setBasePath(department.getFullPathName());
        OSS oss = new OSSClientBuilder().build(bucket.getEndpoint(), bucket.getAccessKeyId(), bucket.getAccessKeySecret());
        userInfo.setOssClient(oss);
        userInfo.setUserId(user.getId());
        return userInfo;
    }

    @Resource
    private SysUserTokenService sysUserTokenService;
    @Resource
    private SysUserService sysUserService;

    @Override
    public User validateUserToken(String accessToken) {
        //根据accessToken，查询用户信息
        UserToken appToken = queryByToken(accessToken);
        SysUserTokenEntity sysToken = sysUserTokenService.getOne(new QueryWrapper<SysUserTokenEntity>().eq("token", accessToken));
        //token失效
        if (appToken == null || appToken.getExpireTime().getTime() < System.currentTimeMillis()) {
            if (sysToken == null || sysToken.getExpireTime().getTime() < System.currentTimeMillis()) {
                throw new IncorrectCredentialsException("token失效，请重新登录");
            }
        }
        User appUser = null;
        if (sysToken != null) {
            SysUserEntity sysUser = sysUserService.getById(sysToken.getUserId());
            appUser = getOne(new QueryWrapper<User>().eq("username", sysUser.getUsername()));
        } else {
            //查询用户信息
            appUser = queryUser(appToken.getUserId());
        }
        //账号锁定
        if (appUser.getStatus() == 1) {
            throw new LockedAccountException("账号已被锁定,请联系管理员");
        }
        return appUser;
    }

    @Resource
    private EnterpriseService enterpriseService;

    @Override
    public void save(EntSaveRequest form) {
        User user = new User();
        Assert.isTrue(!StringUtils.isEmpty(form.getAdminAccount()), "用户账号不可为空");
        user.setUsername(form.getAdminAccount());
        Assert.isTrue(!StringUtils.isEmpty(form.getName()), "企业名不可为空");
        user.setDeptName(form.getName());
        user.setDeptFullName(form.getName());
        user.setName(form.getName());
        //sha256加密
        String salt = RandomStringUtils.randomAlphanumeric(20);
        Assert.isTrue(!StringUtils.isEmpty(form.getAdminPassword()), "用户密码不可为空");
        user.setPassword(new Sha256Hash(form.getAdminPassword(), salt).toHex());
        user.setSalt(salt);
        user.setStatus(0);
        Enterprise enterpriseDB = enterpriseService.getOne(new QueryWrapper<Enterprise>().eq("business_code", form.getBusinessCode()));
        user.setEntName(form.getName());
        user.setEntId(enterpriseDB.getId());
        this.save(user);

        //补充企业主管id
        User userDB = getOne(new QueryWrapper<User>().eq("ent_id", enterpriseDB.getId()));
        enterpriseDB.setAdminId(userDB.getId());
        enterpriseService.updateById(enterpriseDB);
    }

    @Override
    public PageUtils queryPage(Long entId, Map<String, Object> params) {
        String name = (String) params.get("username");

        IPage<User> page = this.page(
                new Query<User>().getPage(params),
                new QueryWrapper<User>()
                        .like(org.apache.commons.lang3.StringUtils.isNotBlank(name), "name", name).eq("ent_id", entId)
        );
        return new PageUtils(page);
    }

    @Override
    public void save(UserSaveReq req) {
        User user = new User();
        user.setId(req.getId());
        user.setName(req.getName());
        user.setDeptId(req.getParentId());
        SysUserEntity sysUser = (SysUserEntity) SecurityUtils.getSubject().getPrincipal();
        user.setEntId(sysUser.getEntId());
        user.setUsername(req.getUsername());
        user.setStatus(req.getStatus());
        if (req.getId() != null) {
            User userDB = getById(req.getId());
            user.setPassword(new Sha256Hash(req.getPassword(), userDB.getSalt()).toHex());
        }else {
            String salt = RandomStringUtils.randomAlphanumeric(20);
            user.setSalt(salt);
            user.setPassword(new Sha256Hash(req.getPassword(), salt).toHex());
        }
        user.setEntName(sysUser.getEntName());
        Department dept = departmentService.getById(req.getParentId());
        user.setDeptName(dept.getName());
        user.setDeptFullName(dept.getFullPathName());
        saveOrUpdate(user);
    }
}
